package com.xxc.exam.controller

import com.xxc.common.const.NOW
import com.xxc.common.exceptions.ParameterInvalidException
import com.xxc.common.util.ExcelUtil
import com.xxc.common.util.FileUDUtil
import com.xxc.exam.constant.QuesConst
import com.xxc.exam.entity.CategoryEntity
import com.xxc.exam.entity.ManagerEntity
import com.xxc.batis.vo.PageVO
import com.xxc.exam.entity.QuestionEntity
import com.xxc.exam.entity.dto.QuestionDto
import com.xxc.exam.entity.pojo.Manager
import com.xxc.exam.entity.pojo.Question
import com.xxc.exam.entity.vo.QuestionVO
import com.xxc.exam.service.QuestionService
import com.xxc.batis.qo.PageQO
import com.xxc.common.exceptions.DataConflictException
import com.xxc.exam.entity.dto.QuestionBatchDto
import com.xxc.exam.service.CategoryService
import com.xxc.response.anotation.OriginResponse
import com.xxc.response.anotation.ResponseResult
import com.xxc.validate.group.UpdateGroup
import org.slf4j.LoggerFactory
import org.springframework.beans.BeanUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import java.math.BigInteger
import org.springframework.web.multipart.MultipartFile
import java.lang.StringBuilder
import java.sql.Timestamp
import java.util.*
import kotlin.collections.HashMap


@ResponseResult
@RestController
class QuestionController {

    val logger = LoggerFactory.getLogger(QuestionController::class.java)

    @Autowired
    lateinit var questionService: QuestionService

    @Autowired
    lateinit var categoryService: CategoryService

    /**
     * 获取题目信息
     * @param pageSize 每一页的大小
     * @param curPage 当前页
     * @param prop 排序的属性
     * @param isAsc 是否正序
     */
    @GetMapping("/questions")
    fun getQuestions(@RequestParam pageSize:Int,@RequestParam curPage:Int,@RequestParam isAsc:Boolean,@RequestParam prop:String,@SessionAttribute auth: Manager): PageVO<QuestionVO> {
        val questions = questionService.findWithPage(PageQO(curPage, pageSize,prop,isAsc,Question(creatorId = auth.id!!)))
        questions.data.forEach {
            it.category?.name = categoryService.getFullPathName(it.category?.id!!)
        }
        return questions
    }

    /**
     * 删除问题
     * @param ids 题目的id
     */
    @DeleteMapping("/questions")
    fun delQuestions(@RequestParam("ids") ids:Array<BigInteger>)
    {
        for (id in ids) {
            println(id)
        }
        return questionService.delQuestions(ids)
    }

    /**
     * 通过excel添加用户
     */
    @PostMapping("/questions/excel")
    fun addQuestionWithExcel(@RequestParam("file") file:MultipartFile,@SessionAttribute("auth") creator:Manager){
        val sheetsData = ExcelUtil.getSheetsData(file.inputStream, file.originalFilename!!)
        val singleList = sheetsData["单选题"]
        val multiList = sheetsData["多选题"]
        var singleQues:List<QuestionEntity>? = null
        var multiQues :List<QuestionEntity>? = null
        singleList?.let {
            singleQues = handleSingleQues(it,creator.id!!,QuesConst.Type.SINGLE_SELECT)
        }
        multiList?.let {
            multiQues = handleSingleQues(it,creator.id!!,QuesConst.Type.MULTI_SELECT)
        }
        val questions:MutableList<QuestionEntity> = mutableListOf()
        singleQues?.let {
            questions.addAll(it)
        }
        multiQues?.let {
            questions.addAll(it)
        }
        if (questions.isEmpty())
            throw ParameterInvalidException("题目为空！！")
        addQuestions(questions)

    }

    @PostMapping("/question/person")
    fun addQuestionWithPerson(dto:QuestionDto, @SessionAttribute("auth") auth:Manager){
        val question = reflectQues(dto,auth.id!!)
        questionService.insert(question)
    }

    private fun handleSingleQues(list: List<List<String?>>,creatorId:BigInteger,type:Int): List<QuestionEntity> {
        val owner = ManagerEntity(id = creatorId)
        val questions = List(list.size - 1){ QuestionEntity() }
        // 当list不足两行时，为空表
        if(list.size < 2)
            return emptyList()
        val header = list[0]
        list.subList(1,list.size).forEachIndexed {index,row->
            val rowNum = index+2
            val ques = questions[index]
            if(row[0] == null || row[0]!!.isBlank())
                throw ParameterInvalidException("单选题中第$rowNum 行题目的题干不能为空")
            ques.title = row[0]
            when(row[row.size - 1]?:"简单")
            {
                "简单" -> ques.level = QuesConst.Level.SIMPLE
                "普通" -> ques.level = QuesConst.Level.NORMAL
                "困难" -> ques.level = QuesConst.Level.DIFFICULT
            }
            val category = row[row.size - 2]
            ques.category = CategoryEntity.DEFAULT(creatorId)
            // 如果表中的分类不为空和空白串则为表中的分类
            if( !(category == null || category.isBlank()) )
                ques.category!!.name = category
            ques.analysis = row[row.size - 3]?:""

            val answer = row[row.size - 4]
            if(answer == null || answer.isBlank())
                throw ParameterInvalidException("答案不能为空")
            ques.answer = answer
            if((row.size - 5 - 1) < 1)
            {
                throw ParameterInvalidException("至少要有两个选项")
            }
            val sb = StringBuilder()
            for( i in 1 .. (row.size - 5))
            {
                //将选项封装成 A题干|B题干  的样子
                if(row[i] == null || row[i]!!.isBlank())
                    continue
                sb.append(header[i]!!.trim().split(" ")[1])
                sb.append(row[i])
                sb.append('|')
            }
            var options = sb.toString()
            // 去除末尾的|
            options = options.substring(0,options.length - 1)
            ques.options = options
            // 设为单选类型
            ques.type = type
            // 设置创建时间更新时间为当前时间
            ques.gmtCreate = Timestamp.from(Date().toInstant())
            ques.gmtModified = Timestamp.from(Date().toInstant())
            ques.creator = owner
        }
        return questions
    }



    fun addQuestions (questions:List<QuestionEntity>) {
        questionService.addQuestions(questions)
    }

    @PutMapping("/question")
    fun editQuestion(dto:QuestionDto, @SessionAttribute("auth") auth:Manager){
        if(dto.id == null) {
            throw ParameterInvalidException("该题目不存在")
        }
        val question = reflectQues(dto,auth.id!!)
        questionService.updateQuestion(question)
    }



    /**
     * 在更新时将Dto转化为entity
     * @throws ParameterInvalidException 一些非空的字段为空时抛出，同时当dto.categoryId == null时抛出
     */
    private fun reflectQues(dto: QuestionDto, creator:BigInteger):Question {
        val question = Question()
        if(dto.content.isNullOrBlank())
        {
            throw ParameterInvalidException("题目的内容不能为空")
        }
        question.title = dto.content
        if(dto.options.isNullOrBlank())
        {
            throw ParameterInvalidException("题目的选项不能为空")
        }else{
            val split = dto.options!!.split("|")
            val stringBuilder = StringBuilder()
            split.forEachIndexed{index,value ->
                stringBuilder.append('A'+index).append(value).append('|')
            }
            if(stringBuilder.isNotEmpty())
                stringBuilder.deleteCharAt(stringBuilder.length - 1)
            dto.options = stringBuilder.toString()
        }
        if(dto.answer.isNullOrBlank())
        {
            throw ParameterInvalidException("题目的答案不能为空")
        }else{
            dto.answer = handleAnswer(dto.answer!!,dto.type!!)
        }
        BeanUtils.copyProperties(dto,question)
        val creatorId = dto.creator?:creator
        question.creatorId = creatorId
        if(dto.category == null)
        {
            throw ParameterInvalidException("题目的分类不能为空")
        }
        question.categoryId = dto.category
        //更新时间
        question.gmtModified = NOW()
        return question
    }

    /**
     * 根据题目类型来处理回答
     */
    private fun handleAnswer(answer: String, type: Int):String {
        when(type)
        {
            QuesConst.Type.SINGLE_SELECT -> {
                return ('A' + answer.toInt()).toString()
            }
            QuesConst.Type.MULTI_SELECT -> {
                val answers = answer.split(",")
                val stringBuilder = StringBuilder()
                answers.forEach {
                    stringBuilder.append('A'+it.toInt())
                }
                return stringBuilder.toString()
            }
        }
        throw DataConflictException("question type is not permit")
    }


    @GetMapping("/questions/template")
    @OriginResponse
    fun download(@RequestHeader("User-Agent") agent:String): ResponseEntity<ByteArray> {
        return FileUDUtil.downloadFile("excel","知题网-试题模版.xls",agent)
    }

    @PutMapping("/questions")
    fun batchUpdate(@Validated(UpdateGroup::class) questions:QuestionBatchDto){
       questionService.updateQuestions(questions)
    }

    @GetMapping("/categoryQues/count")
    fun countCategoriesQues(@RequestParam categories:List<BigInteger>,@SessionAttribute auth:Manager,@RequestParam type:Int):HashMap<Int,Int> {
        if(categories.isEmpty())
        {
            throw ParameterInvalidException("必须选择至少一个分类!")
        }
        return questionService.countCategoriesQues(categories,auth.id!!,type)
    }
}